package com.jeesuite.admin.controller.api;

import java.io.BufferedOutputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.xml.sax.InputSource;

import com.jeesuite.admin.component.CryptComponent;
import com.jeesuite.admin.dao.entity.AppEntity;
import com.jeesuite.admin.dao.entity.AppSecretEntity;
import com.jeesuite.admin.dao.entity.AppSecretEntity.SecretType;
import com.jeesuite.admin.dao.entity.AppconfigEntity;
import com.jeesuite.admin.dao.mapper.AppEntityMapper;
import com.jeesuite.admin.dao.mapper.AppconfigEntityMapper;
import com.jeesuite.admin.dao.mapper.OperateLogEntityMapper;
import com.jeesuite.admin.exception.JeesuiteBaseException;
import com.jeesuite.admin.model.WrapperResponseEntity;
import com.jeesuite.admin.util.ConfigStateHolder;
import com.jeesuite.admin.util.ConfigStateHolder.ConfigState;
import com.jeesuite.admin.util.SecurityUtil;
import com.jeesuite.common.json.JsonUtils;


@Controller
@RequestMapping("/api")
public class ConfigCenterApiController {

	private @Autowired AppconfigEntityMapper appconfigMapper;
	private @Autowired AppEntityMapper appMapper;
	private @Autowired OperateLogEntityMapper operateLogMapper;
	private @Autowired CryptComponent cryptComponent;
	
	@RequestMapping(value = "download_config_file", method = RequestMethod.GET)
	public void downConfigFile(HttpServletResponse response,
			                     @RequestParam(value = "appName") String appName,
			                     @RequestParam(value = "env") String env,
			                     @RequestParam(value = "version",required = false) String version,
			                     @RequestParam(value = "fileName") String fileName){
		
		Map<String, Object> queyParams = new HashMap<>();
		queyParams.put("env", env);
		queyParams.put("name", fileName);
		queyParams.put("version", version);
		//先查全局的
		queyParams.put("appName", appName);
		
		List<AppconfigEntity> configList = appconfigMapper.findByQueryParams(queyParams);
		
		if(configList == null || configList.isEmpty()){
			throw new JeesuiteBaseException(1001, "配置不存在");
		}
		OutputStream output = null;
		try {
			AppconfigEntity config = configList.get(0);
			String content = config.getContents();
			response.addHeader("Content-Disposition", "attachment;filename=" + new String(config.getName().getBytes()));
			response.addHeader("Content-Length", "" + content.length());
			output = new BufferedOutputStream(response.getOutputStream());
			response.setContentType("application/octet-stream");
			byte[] bytes = content.getBytes();
			output.write(bytes);
			output.flush();
			
			operateLogMapper.insertSelective(SecurityUtil.getOperateLog().addBizData("env", env).addBizData("fileName", fileName).addBizData("appName", appName));
		} catch (Exception e) {
			throw new JeesuiteBaseException(9999, "下载失败");
		}finally {			
			if(output != null){
				try {output.close(); } catch (Exception e) {}
			}
		}
	}
	
	@RequestMapping(value = "fetch_all_configs", method = RequestMethod.GET)
	public @ResponseBody Map<String, Object> downConfigFile(  @RequestParam(value = "appName") String appName,
			                     @RequestParam(value = "env") String env,
			                     @RequestParam(value = "version",required = false) String version){
		
		if(StringUtils.isBlank(version))version = "0.0.0";
		
		AppEntity appEntity = appMapper.findByName(appName);
		if(appEntity == null)throw new JeesuiteBaseException(1001, "app不存在");
		
		Map<String, Object> queyParams = new HashMap<>();
		queyParams.put("env", env);
		queyParams.put("version", version);
		//先查全局的
		queyParams.put("appName", "global");
		
		List<AppconfigEntity> globalConfigs = appconfigMapper.findByQueryParams(queyParams);
		//再查应用的
		queyParams.put("appName", appName);
        List<AppconfigEntity> appConfigs = appconfigMapper.findByQueryParams(queyParams);
		
		if(globalConfigs.isEmpty() &&  appConfigs.isEmpty()){
			throw new JeesuiteBaseException(1001, "配置不存在");
		}
		
		Map<String, Object> result = new HashMap<>();
		
        for (AppconfigEntity config : globalConfigs) {
			parseConfigToKVMap(result, config);
		}
        
        for (AppconfigEntity config : appConfigs) {
			parseConfigToKVMap(result, config);
		}
        
        AppSecretEntity secretEntity = cryptComponent.getAppSecret(appEntity.getId(), env, SecretType.DES.name());
        
        if(secretEntity != null){
        	result.put("jeesuite.configcenter.encrypt-secret", secretEntity.getSecretKey());
        }
        
        operateLogMapper.insertSelective(SecurityUtil.getOperateLog().addBizData("env", env).addBizData("appName", appName));
		return result;
	}
	
	@RequestMapping(value = "notify_final_config", method = RequestMethod.POST)
	public @ResponseBody ResponseEntity<WrapperResponseEntity> notifyFinalConfig(@RequestBody Map<String, String> params){
		ConfigStateHolder.add(new ConfigState(params));
		return new ResponseEntity<WrapperResponseEntity>(new WrapperResponseEntity(true),HttpStatus.OK);
	}

	@SuppressWarnings("unchecked")
	private void parseConfigToKVMap(Map<String, Object> result, AppconfigEntity config) {
		if(config.getType() == 1){
			if(config.getName().toLowerCase().endsWith(".xml")){
				parseDataFromXML(result,config.getContents());
			}else{				
				parseFromProps(result, config.getContents());
			}
		}else if(config.getType() == 2){
			result.put(config.getName(), config.getContents());
		}else if(config.getType() == 3){
			Map<String,Object> configs = JsonUtils.toObject(config.getContents(), Map.class);
			result.putAll(configs);
		}
		
		//替换引用
		String value;
		for (String key : result.keySet()) {
			value =  StringUtils.trimToEmpty(result.get(key).toString());
			if(value.contains("${")){
				setReplaceHolderRefValue(result,key,value);
			}
		}
	}

	private static void setReplaceHolderRefValue(Map<String, Object> result, String key, String value) {
		
		String[] segments = value.split("\\$\\{");
		String seg;
		
		StringBuilder finalValue = new StringBuilder();
		for (int i = 0; i < segments.length; i++) {
			seg = StringUtils.trimToNull(segments[i]);
			if(StringUtils.isBlank(seg))continue;
			
			if(seg.contains("}")){				
				String refKey = seg.substring(0, seg.indexOf("}")).trim();
				
				String refValue = result.containsKey(refKey) ? result.get(refKey).toString() : "${" + refKey + "}";
				finalValue.append(refValue);
				
				String[] segments2 = seg.split("\\}");
				if(segments2.length == 2){
					finalValue.append(segments2[1]);
				}
			}else{
				finalValue.append(seg);
			}
		}
		
		result.put(key, finalValue.toString());
	}

	public void parseFromProps(Map<String, Object> result, String content) {
		String[] lines = content.split("\n");
		for (String line : lines) {
			if(StringUtils.isBlank(line) || line.startsWith("#") || line.indexOf("=") < 0)continue;
			//考虑 value包含=的情况
			String key = line.substring(0, line.indexOf("=")).trim();
			String value = line.substring(line.indexOf("=") + 1).trim();
			if(StringUtils.isNotBlank(value)){	
				result.put(key, value);
			}
		}
	}

	private void parseDataFromXML(Map<String, Object> result, String xmlContents) {
		 Document doc = null;
		try {
            //doc = DocumentHelper.parseText(xmlContents);
			SAXReader reader = new SAXReader();
			 //忽略dtd验证
			reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); 
            InputSource source = new InputSource(new StringReader(xmlContents));
		    source.setEncoding("UTF-8");
		    doc = reader.read(source);
            Element rootElt = doc.getRootElement(); 
            Iterator<?> iter = rootElt.elementIterator("entry"); 
            // 遍历head节点
            while (iter.hasNext()) {
                Element elm = (Element) iter.next();
                String stringValue = elm.getStringValue();
                if(StringUtils.isNotBlank(stringValue)){                	
                	result.put(elm.attribute("key").getStringValue(), stringValue);
                }
            }
        } catch (Exception e) {
        	throw new RuntimeException(e);
        }
	}
	
	public static void main(String[] args) throws Exception {
		
		Map<String, Object> result = new HashMap<>();
		result.put("spring.cloud.client.ipAddress", "10.121.10.111");
		result.put("spring.application.name", "demo");
		result.put("server.port", "8002");
		//
		String key = "instance.id";
		String value = "${spring.cloud.client.ipAddress}->${spring.application.name}:${server.port}";
		result.put(key, value);
		
		setReplaceHolderRefValue(result, key, value); 
		
		System.out.println(result.get(key));
		
		key = "instance.id";
		value = "127.0.0.1:${server.port}";
		result.put(key, value);
		
		setReplaceHolderRefValue(result, key, value); 
		
		System.out.println(result.get(key));
	}

}
